﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Win10_1607版本号计算器
{
    public partial class formula : Form
    {
        Stack<string> stack;//运算符号的栈
        Queue<string> queue;//后缀的队列
        /**
         * 通过栈来实现一个表达式的计算
         * 将前缀表达式转化为后缀表达式
         * 对后缀表达式进行计算
         * */

        //将前缀表达式转化为后缀表达式
        public void ex_dis()
        {
            /**
             * 1.遍历中缀表达式

　　         * 2.如果当前中缀元素为操作数，则直接将此操作数“输出”到后缀表达式尾端
        
　　         * 3.如果当前中缀元素为'*'，'/'或'('，直接push入操作符栈

　　         * 4.如果当前中缀元素为')'，则依次pop出栈顶操作符，“输出”到后缀表达式尾端，直至pop得到的是一个'('才停止，并丢弃该'('

　　         * 5.如果当前中缀元素为'+'或'-'，则依次pop出栈顶操作符、“输出”到后缀表达式尾端，直至栈底（栈空）或pop得到了一个'('，若pop得到一个'('，将'('重新push入栈。达到这两个条件之一后，将此操作符（'+'或'-'）入栈。

　　         * 6.如果当前中缀元素为'='，则依次pop出栈顶操作符、“输出”到后缀表达式尾端，直至栈底（栈空）。
             * */
            string[] expression =this.textBox1.Text.Split(' ');//获得表达式
            
            foreach (string ch in expression)
            {
                if( ch =="*" || ch =="/" || ch == "(")//如果当前中缀元素为'*'，'/'或'('，直接push入操作符栈
                {
                    stack.Push(ch);
                }
                else
                {
                    if (ch == ")")//如果当前中缀元素为')'，则依次pop出栈顶操作符，“输出”到后缀表达式尾端，直至pop得到的是一个'('才停止，并丢弃该'('
                    {
                        do
                        {
                            queue.Enqueue(stack.Pop());
                        } while (stack.Peek()!="(");
                        stack.Pop();//丢弃该'('
                    }
                    else
                    {
                        if (ch == "+" || ch == "-")//如果当前中缀元素为'+'或'-'，则依次pop出栈顶操作符、“输出”到后缀表达式尾端，直至栈底（栈空）或pop得到了一个'('，若pop得到一个'('，将'('重新push入栈。达到这两个条件之一后，将此操作符（'+'或'-'）入栈。
                        {
                            if (stack.Count != 0)
                            {
                              //  MessageBox.Show(stack.Peek()+stack.Count.ToString());
                                while (stack.Peek() != "(")
                                {
                                     //   MessageBox.Show("取了一次！");
                                        queue.Enqueue(stack.Pop());
                                       if (stack.Count == 0)
                                       {
                                        break;
                                       }
                                }
                                stack.Push(ch);
                            }
                            else
                            {
                                stack.Push(ch);
                            }
                        }
                        else
                        {
                            if (ch == "=")//如果当前中缀元素为'='，则依次pop出栈顶操作符、“输出”到后缀表达式尾端，直至栈底（栈空）。
                            {
                                while (stack.Count != 0)
                                {
                                  //  MessageBox.Show("a");
                                    queue.Enqueue(stack.Pop());
                                }
                            }
                            else//其他的数字直接入后缀表达式
                            {
                                queue.Enqueue(ch);
                            }
                        }
                    }
                }

            }
        }

        //计算后缀表达式
        /**
         * 将后缀表达式从左到右依次遍历，如果当前元素为数字则入（操作数）栈，
         * 如果为操作符，则pop出栈顶两个元素（第一次pop出的是右操作数，第二次pop出的是左操作数）进行运算，
         * 然后将计算结果再次入栈，直至表达式结束，此时操作数栈内理应只剩一个元素即表达式结果。
         * 
         * */
        public int count ()
        {
            Stack<int> numstack = new Stack<int>();//只放数值
            
            foreach(string ch in queue)
            {
                if (isNum(ch))//不是数字
                {

                  //  MessageBox.Show("放入栈的数值为：" + Convert.ToInt32(ch.ToString()).ToString());
                    numstack.Push(Convert.ToInt32(ch.ToString()));
                   // MessageBox.Show("放入了一次");
                }
                else//非数值，取出数值计算后在入栈
                {
                    int rigth = numstack.Pop();//第一次取出来的是右值
                    int left = numstack.Pop();//第二次为左值
                  //  MessageBox.Show("取出来了一次");
                    switch (ch)
                    {
                        case "+":
                            numstack.Push(left + rigth);
                            break;
                        case "-":
                            numstack.Push(left - rigth);
                            break;
                        case "*":
                            numstack.Push(left * rigth);
                            break;
                        case "/":
                            numstack.Push(left / rigth);
                            break;
                    }
                }
                
            }
            return numstack.Pop();
        }
        public formula()
        {
            InitializeComponent();
            stack = new Stack<string>();//初始化栈
            queue = new Queue<string>();//初始化队列
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {//( 2 - 2 ) =
            try
            {
                this.ex_dis();

                int num = this.count();
                this.textBox1.Text += num.ToString();
            }
            catch
            {
                MessageBox.Show("输入格式不正确！");//出现问题直接甩锅个用户。
                this.textBox1.Text = "";
                MessageBox.Show("使用法则：\n1.必须全部使用英文符号，不支持中文符号。\n2.每一个数字符号直接必须用一个空格隔开。\n3.最后必须要有一个等号结尾！");

            }




        }

        //写一个函数判断分割后的字符串是否为数字
        public bool isNum(string str)
        {
            char[] symbols = {'+','-','*','/' };
            foreach(char symbol in symbols)
            {
                if (str.Contains(symbol))//含有符号说明不为数字
                {
                    return false;
                }
            }
            return true;
        }

        private void label1_Click(object sender, EventArgs e)
        {

        }

        private void button2_Click(object sender, EventArgs e)
        {
            this.textBox1.Text = "";
        }

        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            MessageBox.Show("使用法则：\n1.必须全部使用英文符号，不支持中文符号。\n2.每一个数字符号直接必须用一个空格隔开。\n3.最后必须要有一个等号结尾！");
        }
    }
}
